// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: leon

#include "coin2/exchange/coingecko/feed_v3/processor.h"

#include <string>
#include <utility>

#include "coin2/exchange/base/api_util/json_schema.h"
#include "coin2/exchange/util/json_util.h"

namespace coin2::exchange::coingecko::feed_v3::impl {

void CoingeckoFeedProcessor::OnTopicRecord(
    const base::executor::TopicRecordPacket& packet) {
  upd_mgr_.onBeginPacket(packet);

  rapidjson::Document document;
  document.Parse(packet.payload.data());
  if (document.HasParseError()) {
    THROW() << "JSON parse error: " << GetParseError_En(document.GetParseError());
  }

  if (parser_config_.validate_schema() && schema_) {
    schema_->AcceptOrThrow(document);
  }

  if (document.HasMember("url")) {
    // only support market analysis
    if (document["data"].IsObject()){
      const auto& data = document["data"];
      std::string native_symbol = data["id"].GetString();
      if (!upd_mgr_.is_symbol_registered(native_symbol)) {
        return;
      }
      auto* market_analysis = upd_mgr_.GetMarketAnalysisMutable();
      market_analysis->Clear();
      market_analysis->timestamp = TimestampFromIso8601(data["last_updated"].GetString());
      if (!data["market_data"]["total_supply"].IsNull()) {
        market_analysis->total_supply = data["market_data"]["total_supply"].GetDouble();
      }
      if (!data["market_data"]["max_supply"].IsNull()) {
        market_analysis->max_supply = data["market_data"]["max_supply"].GetDouble();
      }
      market_analysis->circulating_supply = data["market_data"]["circulating_supply"].GetDouble();
      market_analysis->market_cap_in_usd = data["market_data"]["market_cap"]["usd"].GetDouble();
      if (!data["market_data"]["total_value_locked"].IsNull()) {
        market_analysis->tvl_in_usd = data["market_data"]["total_value_locked"]["usd"].GetDouble();
      }
      market_analysis->total_volume_in_usd = data["market_data"]["total_volume"]["usd"].GetDouble();
      if (data.HasMember("tickers") && data["tickers"].IsArray()) {
        const auto ticker_arr = data["tickers"].GetArray();
        std::unordered_map<std::string, int64_t> exchange_index_map;
        int64_t exchange_cnt = 0;
        for (rapidjson::SizeType i = 0; i < ticker_arr.Size(); i++) {
          if (ticker_arr[i].IsObject()) {
            if (ticker_arr[i].HasMember("target_coin_id") && ticker_arr[i]["target_coin_id"].GetString() == native_symbol) {
              continue;
            }
            double volume = ticker_arr[i]["volume"].GetDouble();
            double volume_in_usd = ticker_arr[i]["converted_volume"]["usd"].GetDouble();
            std::string exchange_name = ticker_arr[i]["market"]["name"].GetString();          
            if (exchange_index_map.count(exchange_name) > 0) {
              int64_t exchange_index = exchange_index_map[exchange_name];
              market_analysis->volume_per_exchange_list[exchange_index].volume += volume;
              market_analysis->volume_per_exchange_list[exchange_index].volume_in_usd += volume_in_usd;
            } else {
              market_analysis->volume_per_exchange_list.emplace_back(exchange_name, volume, volume_in_usd);
              exchange_index_map[exchange_name] = exchange_cnt;
              exchange_cnt++;
            }
          }
        }
      }
      upd_mgr_.PublishMarketAnalysis(native_symbol);
  }
  } else {
    LOG(INFO) << "[Coingecko Feed Processor] meta msg for " << packet.topic_name << ": "
              << packet.payload.data();
  }
  upd_mgr_.onEndPacket(packet);
}

}  // namespace coin2::exchange::coingecko::feed_v3::impl
